package org.example.study11.deadlyembrace;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TryLockSolution {
    // 使用ReentrantLock代替synchronized，因为ReentrantLock提供了tryLock方法
    // 必须使用Lock接口的实现类，synchronized不支持非阻塞的锁获取
    private static final Lock lock1 = new ReentrantLock();
    private static final Lock lock2 = new ReentrantLock();

    public static void main(String[] args) {
        // 创建线程1：尝试获取lock1然后lock2
        Thread t1 = new Thread(() -> {
            processWithTryLock("线程1", lock1, lock2);
        });

        // 创建线程2：尝试获取lock2然后lock1 - 注意这里顺序与线程1不同
        // 但tryLock机制可以处理这种情况
        Thread t2 = new Thread(() -> {
            processWithTryLock("线程2", lock2, lock1);
        });

        t1.start();
        t2.start();
    }

    /**
     * 使用tryLock机制安全地获取多个锁
     * 核心思想：如果获取部分锁失败，就释放已持有的锁，避免死锁
     * @param threadName 线程名称，用于日志
     * @param firstLock 第一个要尝试获取的锁
     * @param secondLock 第二个要尝试获取的锁
     */
    private static void processWithTryLock(String threadName, Lock firstLock, Lock secondLock) {
        // 重试机制：如果一次获取失败，可以重试多次
        final int MAX_RETRIES = 3;
        int retryCount = 0;

        // 重试循环
        while (retryCount < MAX_RETRIES) {
            System.out.println(threadName + ": 第" + (retryCount + 1) + "次尝试获取锁");

            // 尝试获取第一个锁 - 非阻塞方式，立即返回结果
            // tryLock()是非阻塞的，如果锁不可用立即返回false
            if (firstLock.tryLock()) {
                try {
                    System.out.println(threadName + ": 成功获取第一个锁");

                    // 模拟业务处理
                    try {
                        TimeUnit.MILLISECONDS.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    // 在持有第一个锁的情况下尝试获取第二个锁
                    if (secondLock.tryLock()) {
                        try {
                            System.out.println(threadName + ": 成功获取第二个锁，执行关键业务");
                            performCriticalSection(threadName);
                            return; // 成功执行，退出循环
                        } finally {
                            secondLock.unlock(); // 确保第二个锁被释放
                        }
                    } else {
                        System.out.println(threadName + ": 获取第二个锁失败");
                    }
                } finally {
                    firstLock.unlock(); // 确保第一个锁被释放
                }
            } else {
                System.out.println(threadName + ": 获取第一个锁失败");
            }

            // 获取失败，增加重试计数
            retryCount++;

            // 等待一段时间后重试，避免活锁
            try {
                TimeUnit.MILLISECONDS.sleep(100 + (int)(Math.random() * 100));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println(threadName + ": 达到最大重试次数，放弃执行");
    }

    private static void performCriticalSection(String threadName) {
        System.out.println(threadName + ": 正在执行关键业务代码");
        try {
            TimeUnit.MILLISECONDS.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(threadName + ": 关键业务执行完成");
    }
}